---
title: .family
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

本セクションの前に「[プロバイダとは](/docs/concepts2/providers)」と「[プロバイダの利用方法](/docs/concepts/reading)」のセクションに目を通していただくことをおすすめします。
ここでは「プロバイダ修飾子」の一つである `.family` について詳しく説明します。

`.family` 修飾子の目的は「外部のパラメータをもとに一意のプロバイダを作成すること」です。

次のようなケースでの使用が考えられます。

- [FutureProvider] と `family` を組み合わせて、メッセージ ID から `Message` を取得する。
- プロバイダにアプリの現在のロケール情報を渡して、翻訳文を取得する。

## 使用方法

`.family` 修飾子を付けてプロバイダを作成すると、パラメータが追加されます。
このパラメータはプロバイダのステート（状態）を計算する要素として使用することができます。

例えば `family` と [FutureProvider] を組み合わせることで、メッセージ ID に紐づく `Message` を取得することが可能です。

```dart
final messagesFamily = FutureProvider.family<Message, String>((ref, id) async {
  return dio.get('http://my_api.dev/messages/$id');
});
```

`family` プロバイダをウィジェットなどで利用する際の構文は通常と若干異なります。次の構文ではコンパイル時エラーが出ます。

```dart
Widget build(BuildContext context, WidgetRef ref) {
  // エラー – messagesFamily はプロバイダではありません
  final response = ref.watch(messagesFamily);
}
```

代わりに、次のように `messagesFamily` に引数を渡してください。

```dart
Widget build(BuildContext context, WidgetRef ref) {
  final response = ref.watch(messagesFamily('id'));
}
```

:::info
`.family` 修飾子を使用するプロバイダに、異なる引数を同時に渡すことも可能です。
例えば `titleFamily` プロバイダに異なるロケール情報を渡し、英語とフランス語の翻訳文をそれぞれ取得することができます。

```dart
@override
Widget build(BuildContext context, WidgetRef ref) {
  final frenchTitle = ref.watch(titleFamily(const Locale('fr')));
  final englishTitle = ref.watch(titleFamily(const Locale('en')));

  return Text('fr: $frenchTitle en: $englishTitle');
}
```

:::

## 引数として渡すオブジェクトの等価性

`family` プロバイダを正常に動作させるには、引数として渡すオブジェクトに等価性が定義されている必要があります。

プリミティブ型（bool/int/double/String）か、定数（プロバイダ）もしくは `==` と `hashCode` をオーバーライドしたイミュータブル（不変）オブジェクトのいずれかが理想的です。

### _【重要】_ オブジェクトが一定ではない場合は `autoDispose` 修飾子との併用が望ましい

`family` を使って検索フィールドの入力値をプロバイダに渡す場合、その入力値は頻繁に変わる上に同じ値が再利用されることはありません。
おまけにプロバイダは参照されなくなっても破棄されないのがデフォルトの動作であるため、この場合はメモリリークにつながります。

こうしたメモリリークは `.family` と `.autoDispose` 修飾子を併用することで避けることができます。

```dart
final characters = FutureProvider.autoDispose.family<List<Character>, String>((ref, filter) async {
  return fetchCharacters(filter: filter);
});
```

## `family` プロバイダに複数のパラメータを渡す

`.family` 修飾子はプロバイダに複数のオブジェクトを渡すことができません。

しかし、前述した制限を満たしている限りは _どのような_ オブジェクトでも渡すことができます。

これを利用して、例えば以下のオブジェクトを渡すことでプロバイダに複数のパラメータを間接的に渡すことができます。

- [tuple](http://pub.dev/packages/tuple) パッケージのタプルオブジェクト
- [Freezed] もしくは [built_value](https://pub.dev/packages/built_value) パッケージで生成されたオブジェクト
- [equatable](https://pub.dev/packages/equatable) を使用したオブジェクト

以下は [Freezed] もしくは [equatable] を利用した場合のサンプルコードです。

<Tabs
  groupId="family"
  defaultValue="freezed"
  values={[
    { label: 'Freezed', value: 'freezed', },
    { label: 'Equatable', value: 'equatable', },
  ]}
>

<TabItem value="freezed">

```dart
@freezed
abstract class MyParameter with _$MyParameter {
  factory MyParameter({
    required int userId,
    required Locale locale,
  }) = _MyParameter;
}

final exampleProvider = Provider.autoDispose.family<Something, MyParameter>((ref, myParameter) {
  print(myParameter.userId);
  print(myParameter.locale);
  // userId と locale を使って何かする
});

@override
Widget build(BuildContext context, WidgetRef ref) {
  int userId; // ユーザ ID をどこかで取得する
  final locale = Localizations.localeOf(context);

  final something = ref.watch(
    exampleProvider(MyParameter(userId: userId, locale: locale)),
  );

  ...
}
```

</TabItem>
<TabItem value="equatable">

```dart
class MyParameter extends Equatable  {
  MyParameter({
    required this.userId,
    required this.locale,
  });

  final int userId;
  final Locale locale;

  @override
  List<Object> get props => [userId, locale];
}

final exampleProvider = Provider.family<Something, MyParameter>((ref, myParameter) {
  print(myParameter.userId);
  print(myParameter.locale);
  // userId と locale を使って何かする
});

@override
Widget build(BuildContext context, WidgetRef ref) {
  int userId; // ユーザ ID をどこかで取得する
  final locale = Localizations.localeOf(context);

  final something = ref.watch(
    exampleProvider(MyParameter(userId: userId, locale: locale)),
  );

  ...
}
```
</TabItem>
</Tabs>

[freezed]: https://pub.dev/packages/freezed
[equatable]: https://pub.dev/packages/equatable
[futureprovider]: https://pub.dev/documentation/hooks_riverpod/latest/hooks_riverpod/FutureProvider-class.html
